package com.hexacta.hrs.domain.staffing.relationship.generators;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;

import com.hexacta.hrs.domain.staffing.Particionador;
import com.hexacta.hrs.domain.staffing.Requirement;
import com.hexacta.hrs.domain.staffing.assignment.EmployeeAssignment;
import com.hexacta.hrs.domain.staffing.relationship.RelationshipEnsamblador;
import com.hexacta.hrs.domain.staffing.relationship.RequirementAssignmentRelationship;

public class RequirementAssignmentGenerator {

	/**
	 * 	Calcula y genera todas las relaciones del tipo RequirementAssignment que existen entre los requerimientos de un proyecto y sus recursos asignados.
	 */
	public static List<RequirementAssignmentRelationship> generate(Set<Requirement> originalRequirements, List<EmployeeAssignment>  originalAssignments){
		List<RequirementAssignmentRelationship> requirementAssignments = new ArrayList<RequirementAssignmentRelationship>();

		// Hago una copia de los requerimientos y asignaciones:
		List<Requirement> requirements = new ArrayList<Requirement>(originalRequirements);
		List<EmployeeAssignment> assignments = new ArrayList<EmployeeAssignment>(originalAssignments);

		for(int i = 0; i< assignments.size(); i++){

			EmployeeAssignment assignment = assignments.get(i);

			// Si hay algun requerimiento cuyo rol es igual al de la asignacion y cuyo rango de fechas es superior,
			//	y si hay requerimiento tal que el porcentaje sea mayor o igual al porcentaje de la asignacion:
			Requirement requirement = (Requirement)CollectionUtils.find(requirements, new CumpleRangoDeFechasConPorcentajeMayor(assignment));
			boolean algunoCumpleRangoDeFechasConPorcentajeMayor = (requirement!=null);
			if(algunoCumpleRangoDeFechasConPorcentajeMayor){
				requirements.remove(requirement); // Lo elimino ya que en el proximo paso es particionado en varios requerimientos menores que son agregados a la lista.
				requirements.addAll(RelationshipGeneratorUtil.generarRelacionesDeRequerimientoConPorcentajeMayor(assignment, requirement));
				//Agrego la asignacion en la lista de respuesta.
				requirementAssignments.add(RequirementAssignmentRelationship.createRequirementAssignment(assignment, requirement));
			}

			// Si hay algun requerimiento cuyo rol es igual al de la asignacion y cuyo rango de fechas es superior,
			// y si hay requerimiento tal que el porcentaje sea menor al porcentaje de la asignacion:
			Requirement req = (Requirement)CollectionUtils.find(requirements, new CumpleRangoDeFechasConPorcentajeMenor(assignment));
			boolean algunoCumpleRangoDeFechasConPorcentajeMenor = (req!=null);
			if(!algunoCumpleRangoDeFechasConPorcentajeMayor && algunoCumpleRangoDeFechasConPorcentajeMenor){
				//Agrego la asignacion al final de la lista de asignaciones, con un porcentaje restante (no asignado) =  porc de asig - porc de requerim.
				assignments.add(RelationshipGeneratorUtil.crearAsignacionRestante(assignment, req));

				//Agrego la asignacion en la lista de respuesta.
				requirementAssignments.add(RequirementAssignmentRelationship.createRequirementAssignment(assignment, req));

				//Particiono el req en la cant que sea necesaria, excluyendo la parte ya asignada.
			 	requirements.remove(req);
			 	requirements.addAll(Particionador.particionarExcluyendoInterseccion(req, assignment));
			}

			if(!algunoCumpleRangoDeFechasConPorcentajeMayor && !algunoCumpleRangoDeFechasConPorcentajeMenor){
				// Si se llego hasta aca significa que no existen requerimientos que tengan un intervalo de fechas mayor o igual
				// al intervalo de la asignacion, entonces particiono la asignacion para que entre en requerimientos mas chicos.
				assignments.addAll(RelationshipGeneratorUtil.particionarAsignacionSegunRequerimientos(assignment, requirements));
			}
		}

		// Una vez obtenidas todas las relaciones, intento de fusionar aquellas asignaciones con igual %FTE, rol y empleado, y que son consecutivas.
		RelationshipEnsamblador.unirRelationships(requirementAssignments);

		return requirementAssignments;
	}
}
